<template>
  <div class="container">
    <div class="app-container">
      <!-- 添加角色对话框 -->
      <el-dialog title="添加角色" :visible="dialogVisable" @close="closeDialog">
        <el-form ref="addForm" :model="addRole" :rules="addFormRules" label-width="80px" size="small">
          <el-form-item label="角色名称" prop="name">
            <el-input v-model="addRole.name" type="text" />
          </el-form-item>
          <el-form-item label="启用">
            <el-switch
              v-model="addRole.state"
              :active-value="1"
              :inactive-value="0"
            />
          </el-form-item>
          <el-form-item label="描述" prop="description">
            <el-input v-model="addRole.description" type="textarea" />
          </el-form-item>
          <el-form-item>
            <el-row type="flex" justify="center">
              <el-button type="primary" @click="addRoleBtn">确定</el-button>
              <el-button @click="closeDialog">取消</el-button>
            </el-row>
          </el-form-item>
        </el-form>
      </el-dialog>
      <!-- 添加角色按钮 -->
      <div class="add-role-btn">
        <el-button v-permission="'add-role'" type="primary" size="small" @click="dialogVisable = true">添加角色</el-button>
      </div>
      <!-- 角色列表表格 -->
      <el-table :data="rolelist" size="medium">
        <el-table-column label="角色">
          <template v-slot="{row}">
            <el-input
              v-if="row.isEdit"
              v-model="row.editRow.name"
              type="text"
              size="mini"
            />
            <span v-else>{{ row.name }}</span>
          </template>
        </el-table-column>
        <el-table-column label="状态">
          <template v-slot="{row}">
            <el-switch
              v-if="row.isEdit"
              v-model="row.editRow.state"
              :active-value="1"
              :inactive-value="0"
              size="mini"
            />
            <span v-else>
              {{ row.state === 1 ? "启用" : row.state === 0 ? "禁用" : "无" }}
            </span>
          </template>
        </el-table-column>
        <el-table-column label="描述">
          <template v-slot="{row}">
            <el-input
              v-if="row.isEdit"
              v-model="row.editRow.description"
              type="textarea"
              :rows="1"
              size="mini"
            />
            <span v-else>{{ row.description }}</span>
          </template>
        </el-table-column>>
        <el-table-column label="操作">
          <template v-slot="{row}">
            <el-row v-if="row.isEdit">
              <el-button type="primary" size="mini" @click="onModify(row)">确定</el-button>
              <el-button size="mini" @click="onCancelEdit(row)">取消</el-button>
            </el-row>
            <el-row v-else>
              <el-button size="small" type="text" @click="openAssignPerm(row.id)">权限</el-button>
              <el-button
                style="margin-right: 10px;"
                size="small"
                type="text"
                @click="row.isEdit=true"
              >编辑</el-button>
              <template>
                <el-popconfirm title="确定删除吗？" @onConfirm="deleteRole(row)">
                  <el-button slot="reference" size="small" type="text">删除</el-button>
                </el-popconfirm>
              </template>
            </el-row>
          </template>
        </el-table-column>
      </el-table>
      <!-- 分页工具栏 -->
      <el-row>
        <el-pagination
          layout="sizes, prev, pager, next, total"
          :total="pageParam.total"
          :current-page="pageParam.page"
          :page-size="pageParam.pagesize"
          :page-sizes="[5, 10, 20]"
          @size-change="onSizeChange"
          @current-change="onCurrentChange"
        />
      </el-row>
      <!-- 分配权限对话框 -->
      <el-dialog title="权限" :visible.sync="permDialogVisable">
        <el-tree
          ref="permTree"
          :data="permTreeData"
          node-key="id"
          default-expand-all
          show-checkbox
          :props="{label: 'name'}"
          check-strictly
        />
        <el-row slot="footer" justify="center" type="flex">
          <el-button size="small" type="primary" @click="assignPerm">确定</el-button>
          <el-button size="small" @click="permDialogVisable = false">取消</el-button>
        </el-row>
      </el-dialog>
    </div>
  </div>
</template>
<script>
import { getRoleList, addRole, modifyRole, deleteRole, getRole, assignPerm } from '@/api/role'
import { getPermList } from '@/api/permission'
import { transList2Tree } from '@/utils/date-handle'

export default {
  name: 'Role',
  data() {
    return {
      rolelist: [],
      pageParam: {
        page: 1, // 当前页码
        pagesize: 10, // 每页记录数
        total: 500
      },
      dialogVisable: false,
      // 对话框数据
      addRole: {
        name: '',
        state: 0,
        description: ''
      },
      addFormRules: {
        name: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }],
        description: [{ required: true, message: '角色描述不能为空', trigger: 'blur' }]
      },

      // 分配权限树形数据
      permTreeData: [],
      // 分配权限对话框
      permDialogVisable: false,
      // 分配权限时的角色id
      id: ''
    }
  },
  created() {
    this.getRoleList()
  },
  methods: {
    // 分页获取角色列表
    async getRoleList() {
      const res = await getRoleList(this.pageParam)
      res.rows.forEach(item => {
        // 添加是否编辑属性
        item.isEdit = false
        // 缓存数据，用于编辑时回显，注意必须为深拷贝
        // item.editRow = item 这样写为浅拷贝，且存在循环引用问题
        // 因为item中的属性为基本类型和字符串，因此不存在深拷贝浅拷贝问题
        item.editRow = {
          name: item.name,
          state: item.state,
          description: item.description
        }
      })

      this.rolelist = res.rows
      this.pageParam.total = res.total
    },
    // 每页记录数变化时触发
    onSizeChange(pagesize) {
      this.pageParam.pagesize = pagesize
      this.getRoleList()
    },
    // 页码变化时触发
    onCurrentChange(page) {
      this.pageParam.page = page
      this.getRoleList()
    },
    // 关闭添加角色对话框
    closeDialog() {
      this.dialogVisable = false
      this.$refs.addForm.resetFields()
    },
    // 添加角色
    addRoleBtn() {
      this.$refs.addForm.validate(async(isOk) => {
        if (isOk) {
          await addRole(this.addRole)
          // 回显数据
          this.getRoleList()
          this.$message.success('添加角色成功')
          this.closeDialog()
        }
      })
    },
    // 取消编辑按钮
    onCancelEdit(row) {
      // 恢复缓存数据
      row.editRow = {
        name: row.name,
        state: row.state,
        description: row.description
      }
      // 关闭编辑
      row.isEdit = false
    },
    // 确认编辑按钮
    async onModify(row) {
      // name和desc字段校验
      if (row.editRow.name && row.editRow.description) {
        // 提交数据
        await modifyRole({ id: row.id, ...row.editRow })
        this.$message.success('修改成功')
        // 将当前row的相关属性改为修改之后的
        // 注意，和Java一样，形参的引用不能更改，这种写法是错的
        // 错误写法：row = { ...row.editRow, isEdit: false }
        Object.assign(row, { ...row.editRow, isEdit: false })
      } else {
        this.$message.error('角色名称或角色描述不能为空')
      }
    },
    // 删除角色
    async deleteRole(row) {
      // 调用接口删除
      await deleteRole(row.id)
      this.$message.success('删除成功')
      // 重载数据
      // 若为当前页的最后一个 并且当前页不为1，page--
      if (this.rolelist.length === 1 && this.pageParam.page !== 1) this.pageParam.page--
      this.getRoleList()
    },

    // 分配权限按钮
    async openAssignPerm(id) {
      this.id = id
      // 打开加载
      const loading = this.$loading({
        lock: true,
        text: 'Loading',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)'
      })
      try {
        // 获取权限列表，转为树形数据
        const res = await getPermList()
        this.permTreeData = transList2Tree(res)

        // 回显用户的角色
        const { permIds } = await getRole(id)
        // 等数据准备完毕再关闭加载、打开框
        this.permDialogVisable = true // 这行放后面会导致setCheckedKeys方法异常
        this.$nextTick(() => {
          this.$refs.permTree.setCheckedKeys(permIds)
        })
      } finally {
        // 防止出现异常
        loading.close()
      }
    },

    // 确定分配权限
    async assignPerm() {
      const keys = this.$refs.permTree.getCheckedKeys()
      if (keys.length > 0) {
        await assignPerm({
          id: this.id,
          permIds: keys
        })
        this.$message.success('分配权限成功')
        this.permDialogVisable = false
      } else {
        this.$message.error('请至少分配一个权限')
      }
    }
  }
}
</script>
<style scoped>
.app-container{
  padding: 0 20px;
}
.add-role-btn {
  padding-bottom: 10px;
}
</style>
